package zoningcode

import (
	"demo/mysql"
	"fmt"
	"io/ioutil"
	"net/http"
	"regexp"
	"strings"
	"time"
	"unicode/utf8"

	"golang.org/x/text/encoding/simplifiedchinese"
)

var lastTime int64 = 0

var root string = "http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2020/"

// fetch 根据URL获取页面数据
func fetch(url string) string {
	var duration int64 = 2000
	curTime := time.Now().UnixNano() / int64(time.Millisecond)
	if curTime-lastTime < duration {
		fmt.Println(time.Now().Format("2006-01-02 15:04:05"), "Sleep Url", url)
		time.Sleep(time.Duration((duration + lastTime - curTime) * int64(time.Millisecond)))
	}
	lastTime = time.Now().UnixNano() / int64(time.Millisecond)
	fmt.Println(time.Now().Format("2006-01-02 15:04:05"), "Fetch Url", url)

	client := &http.Client{}

	req, _ := http.NewRequest("GET", url, nil)
	req.Header.Set("User-Agent", "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)")

	resp, err := client.Do(req)
	if err != nil {
		fmt.Println("Http get error:", err)
		return ""
	}
	if resp.StatusCode != 200 {
		fmt.Println("Http status code:", resp.StatusCode)
		return ""
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println("Read error", err)
		return ""
	}

	if !utf8.Valid(body) {
		body, _ = simplifiedchinese.GBK.NewDecoder().Bytes(body)
	}

	return string(body)
}

// parseProvincePage 解析省级页面
func parseProvincePage() {
	// 判断省级页面获取是否完毕
	mysql.InitTable()
	parentCodeArr := mysql.SelectNotDone(0)
	if len(parentCodeArr) == 0 || parentCodeArr[0].IsDone == 1 {
		return
	}
	mysql.DeleteChildren("", 1)

	// 抓取
	body := fetch(root + "index.html")
	body = strings.Replace(body, "\n", "", -1)
	body = strings.Replace(body, "<br/>", "", -1)
	rp := regexp.MustCompile(`<td><a href='([^']+).html'>([^<]+)</a></td>`)
	items := rp.FindAllStringSubmatch(body, -1)
	codeArr := []*mysql.ZoningCode{}
	for _, item := range items {
		// [<td><a href='11.html'>北京市</a></td> 11 北京市]
		obj := new(mysql.ZoningCode)
		obj.ZoningCode = item[1] + "0000000000"
		obj.ZoningName = item[2]
		obj.Level = 1
		obj.IsDone = 0
		codeArr = append(codeArr, obj)
	}

	// 入库并更新
	if len(codeArr) > 0 {
		mysql.InsertAll(codeArr)
	}
	mysql.UpdateDone(parentCodeArr[0].ZoningCode)
}

// parseCityPage 解析市级页面
func parseCityPage() {
	for {
		codeArr := mysql.SelectNotDone(1)
		if len(codeArr) == 0 {
			break
		}
		for _, code := range codeArr {
			doParseCityPage(code)
		}
	}
}

// doParseCityPage 执行解析市级页面
func doParseCityPage(code *mysql.ZoningCode) {
	rs := []rune(code.ZoningCode)
	provinceCode := string(rs[:2])

	// 删除子区划
	mysql.DeleteChildren(provinceCode, 2)

	// 抓取
	body := fetch(root + provinceCode + ".html")
	body = strings.Replace(body, "\n", "", -1)
	body = strings.Replace(body, "<br/>", "", -1)
	rp := regexp.MustCompile(`<tr class='[^']+'><td>(<a href='[^']+'>)?([\d]+)(</a>)?</td><td>(<a href='[^']+'>)?([^<\d]+)(</a>)?</td></tr>`)
	items := rp.FindAllStringSubmatch(body, -1)
	codeArr := []*mysql.ZoningCode{}
	for _, item := range items {
		obj := new(mysql.ZoningCode)
		obj.ZoningCode = item[2]
		obj.ZoningName = item[5]
		obj.Level = 2
		obj.IsDone = 0
		codeArr = append(codeArr, obj)
	}

	// 入库并更新
	if len(codeArr) > 0 {
		mysql.InsertAll(codeArr)
	}
	mysql.UpdateDone(code.ZoningCode)
}

// parseCountyPage 解析县级页面
func parseCountyPage() {
	for {
		codeArr := mysql.SelectNotDone(2)
		if len(codeArr) == 0 {
			break
		}
		for _, code := range codeArr {
			doParseCountyPage(code)
		}
	}
}

// doParseCountyPage 执行解析县级页面
func doParseCountyPage(code *mysql.ZoningCode) {
	rs := []rune(code.ZoningCode)
	cityCode := string(rs[:4])

	// 删除子区划
	mysql.DeleteChildren(cityCode, 3)

	// 抓取
	body := fetch(root + string(rs[:2]) + "/" + cityCode + ".html")
	body = strings.Replace(body, "\n", "", -1)
	body = strings.Replace(body, "<br/>", "", -1)
	rp := regexp.MustCompile(`<tr class='[^']+'><td>(<a href='[^']+'>)?([\d]+)(</a>)?</td><td>(<a href='[^']+'>)?([^<\d]+)(</a>)?</td></tr>`)
	items := rp.FindAllStringSubmatch(body, -1)
	codeArr := []*mysql.ZoningCode{}
	for _, item := range items {
		obj := new(mysql.ZoningCode)
		obj.ZoningCode = item[2]
		obj.ZoningName = item[5]
		obj.Level = 3
		obj.IsDone = 0
		codeArr = append(codeArr, obj)
	}

	// 入库并更新
	if len(codeArr) > 0 {
		mysql.InsertAll(codeArr)
	}
	mysql.UpdateDone(code.ZoningCode)
}

// parseTownshipPage 解析乡级页面
func parseTownshipPage() {
	for {
		codeArr := mysql.SelectNotDone(3)
		if len(codeArr) == 0 {
			break
		}
		for _, code := range codeArr {
			doParseTownshipPage(code)
		}
	}
}

// doParseTownshipPage 执行解析乡级页面
func doParseTownshipPage(code *mysql.ZoningCode) {
	rs := []rune(code.ZoningCode)
	countyCode := string(rs[:6])

	// 删除子区划
	mysql.DeleteChildren(countyCode, 4)

	// 抓取
	body := fetch(root + string(rs[:2]) + "/" + string(rs[2:4]) + "/" + countyCode + ".html")
	body = strings.Replace(body, "\n", "", -1)
	body = strings.Replace(body, "<br/>", "", -1)
	rp := regexp.MustCompile(`<tr class='[^']+'><td>(<a href='[^']+'>)?([\d]+)(</a>)?</td><td>(<a href='[^']+'>)?([^<\d]+)(</a>)?</td></tr>`)
	items := rp.FindAllStringSubmatch(body, -1)
	codeArr := []*mysql.ZoningCode{}
	for _, item := range items {
		obj := new(mysql.ZoningCode)
		obj.ZoningCode = item[2]
		obj.ZoningName = item[5]
		obj.Level = 4
		obj.IsDone = 0
		codeArr = append(codeArr, obj)
	}

	// 入库并更新
	if len(codeArr) > 0 {
		mysql.InsertAll(codeArr)
	}
	mysql.UpdateDone(code.ZoningCode)
}

// parseVillagePage 解析村级页面
func parseVillagePage() {
	for {
		codeArr := mysql.SelectNotDone(4)
		if len(codeArr) == 0 {
			break
		}
		for _, code := range codeArr {
			doParseVillagePage(code)
		}
	}
}

// doParseVillagePage 执行解析村级页面
func doParseVillagePage(code *mysql.ZoningCode) {
	rs := []rune(code.ZoningCode)
	townshipCode := string(rs[:9])

	// 删除子区划
	mysql.DeleteChildren(townshipCode, 5)

	// 抓取
	body := fetch(root + string(rs[:2]) + "/" + string(rs[2:4]) + "/" + string(rs[4:6]) + "/" + townshipCode + ".html")
	body = strings.Replace(body, "\n", "", -1)
	body = strings.Replace(body, "<br/>", "", -1)
	rp := regexp.MustCompile(`<tr class='[^']+'><td>([\d]+)</td><td>([\d]+)</td><td>([^<\d]+)</td></tr>`)
	items := rp.FindAllStringSubmatch(body, -1)
	codeArr := []*mysql.ZoningCode{}
	for _, item := range items {
		obj := new(mysql.ZoningCode)
		obj.ZoningCode = item[1]
		obj.ZoningName = item[3]
		obj.Level = 5
		obj.IsDone = 1
		codeArr = append(codeArr, obj)
	}

	// 入库并更新
	if len(codeArr) > 0 {
		mysql.InsertAll(codeArr)
	}
	mysql.UpdateDone(code.ZoningCode)
}

// Run 执行
func Run() {
	parseProvincePage()
	parseCityPage()
	parseCountyPage()
	parseTownshipPage()
	parseVillagePage()
}
